	//---------------------------------------------------------------------
	// Includes
	//---------------------------------------------------------------------		
	#include <string>
	#include <Settings.hpp>
	#include <Math/Vector.hpp>
	#include <Libs/rply.h>
	#include <Geometry/Loader.hpp>
	
namespace Geometry {

	//---------------------------------------------------------------------
	// Geometry loader methods	
	//---------------------------------------------------------------------	
	GeometryLoader::GeometryLoader(const std::string& e):extension(e) {
		
	}
	//---------------------------------------------------------------------
	GeometryLoader::~GeometryLoader() { }	
	//---------------------------------------------------------------------
	std::string GeometryLoader::GetExtension() const {
		return extension;
	}	
	

	//-----------------------------------------------------------------------------
	// Types
	//-----------------------------------------------------------------------------			
	struct BuildingBuffer {
		float* vertexBuffer;
		float* normalBuffer;		
		float* tangentBuffer;
		unsigned int* indexBuffer;		
		int* numberOfNormal;
	};	
	//-----------------------------------------------------------------------------
	struct Vertex	{
		Vertex() { }
		Vertex(const Vertex& copy):x(copy.x),y(copy.y),z(copy.z) { }
		float x;
		float y;
		float z;
	};
	typedef std::map< int, Vertex > VertexMap;
	//-----------------------------------------------------------------------------
    // Variable pour la realisation du chargement
    static BuildingBuffer buildingBuffer;
	static VertexMap vertexMap;
	static int currentVertexIndex = 0;
	static int currentTriangleIndex[3];
	static int currentFaceIndex = 0;
	
	//---------------------------------------------------------------------
	// PLY loader methods	
	//---------------------------------------------------------------------
	PLYLoader::PLYLoader(): GeometryLoader("ply") { }
	//---------------------------------------------------------------------
	PLYLoader::~PLYLoader() { }	
	//-----------------------------------------------------------------------------
	static int CoordinateXCallback(p_ply_argument argument)	{
		float x = ply_get_argument_value(argument)*PLY_SCALE_FACTOR;
		buildingBuffer.vertexBuffer[currentVertexIndex*3+0] = x;
		vertexMap[currentVertexIndex].x = x;
		return true;
	}

	//-----------------------------------------------------------------------------
	static int CoordinateYCallback(p_ply_argument argument)	{
		float y = ply_get_argument_value(argument)*PLY_SCALE_FACTOR;
		buildingBuffer.vertexBuffer[currentVertexIndex*3+1] = y;
		vertexMap[currentVertexIndex].y = y;
		return true;
	}

	//-----------------------------------------------------------------------------
	static int CoordinateZCallback(p_ply_argument argument)	{
		float z = ply_get_argument_value(argument)*PLY_SCALE_FACTOR;
		buildingBuffer.vertexBuffer[currentVertexIndex*3+2] = z;
		vertexMap[currentVertexIndex].z = z;
		++currentVertexIndex;
		return true;
	}
	//-----------------------------------------------------------------------------
	int FaceCallback(p_ply_argument argument) {
		// Recuperation des indices des sommets du triangle courant
		long length;
		long value_index;
		ply_get_argument_property(argument, NULL, &length, &value_index);		
		switch (value_index) {
			case 0:
				buildingBuffer.indexBuffer[currentFaceIndex*3+0] = (int)ply_get_argument_value(argument);
				currentTriangleIndex[0] = (int)ply_get_argument_value(argument);
				break;
			case 1:
				buildingBuffer.indexBuffer[currentFaceIndex*3+1] = (int)ply_get_argument_value(argument);
				currentTriangleIndex[1] = (int)ply_get_argument_value(argument);
				break;
			case 2:
				{
				buildingBuffer.indexBuffer[currentFaceIndex*3+2] = (int)ply_get_argument_value(argument);
				currentTriangleIndex[2] = (int)ply_get_argument_value(argument);
				
				//Vertex vertex0;// = vertexMap[ currentTriangleIndex[0] ];
				//Vertex vertex1;// = vertexMap[ currentTriangleIndex[1] ];
				//Vertex vertex2;// = vertexMap[ currentTriangleIndex[2] ];
				//vertex0 = vertexMap.find(currentTriangleIndex[0])->second;
				//vertex1 = vertexMap.find(currentTriangleIndex[1])->second;
				//vertex2 = vertexMap.find(currentTriangleIndex[2])->second;
				
				
				Vector::Vector3 vertex0 = { buildingBuffer.vertexBuffer[currentTriangleIndex[0]*3+0], 
											buildingBuffer.vertexBuffer[currentTriangleIndex[0]*3+1],
											buildingBuffer.vertexBuffer[currentTriangleIndex[0]*3+2] };
				Vector::Vector3 vertex1 = { buildingBuffer.vertexBuffer[currentTriangleIndex[1]*3+0], 
											buildingBuffer.vertexBuffer[currentTriangleIndex[1]*3+1],
											buildingBuffer.vertexBuffer[currentTriangleIndex[1]*3+2] };
				Vector::Vector3 vertex2 = { buildingBuffer.vertexBuffer[currentTriangleIndex[2]*3+0], 
											buildingBuffer.vertexBuffer[currentTriangleIndex[2]*3+1],
											buildingBuffer.vertexBuffer[currentTriangleIndex[2]*3+2] };
				Vector::Vector3 u, v, n;
				Vector::Sub3(u,vertex1,vertex0);
				Vector::Sub3(v,vertex2,vertex0);
				Vector::Cross3(n,u,v);
				Vector::Norm3(n,n);
				
				buildingBuffer.normalBuffer[currentTriangleIndex[0]*3+0] += n[0];
				buildingBuffer.normalBuffer[currentTriangleIndex[0]*3+1] += n[1];
				buildingBuffer.normalBuffer[currentTriangleIndex[0]*3+2] += n[2];
				
				buildingBuffer.normalBuffer[currentTriangleIndex[1]*3+0] += n[0];
				buildingBuffer.normalBuffer[currentTriangleIndex[1]*3+1] += n[1];
				buildingBuffer.normalBuffer[currentTriangleIndex[1]*3+2] += n[2];
				
				buildingBuffer.normalBuffer[currentTriangleIndex[2]*3+0] += n[0];
				buildingBuffer.normalBuffer[currentTriangleIndex[2]*3+1] += n[1];
				buildingBuffer.normalBuffer[currentTriangleIndex[2]*3+2] += n[2];
				
				++buildingBuffer.numberOfNormal[currentTriangleIndex[0]];
				++buildingBuffer.numberOfNormal[currentTriangleIndex[1]];
				++buildingBuffer.numberOfNormal[currentTriangleIndex[2]];
				
				++currentFaceIndex;
				break;
				}
			default:
			    	break;
		}
		return true;
	}
	//-----------------------------------------------------------------------------
	TMeshPointer PLYLoader::LoadFromFile(const std::string& filename) {
	
		// Open file
		long nvertices;
		long ntriangles;
		p_ply plyfile = ply_open(filename.c_str(), NULL);
		if (!plyfile) return false;

		// Read header ply file and affect callbacks
		if (!ply_read_header(plyfile)) return false;
		nvertices =
		ply_set_read_cb(plyfile, "vertex", "x", CoordinateXCallback, NULL, 0);
		ply_set_read_cb(plyfile, "vertex", "y", CoordinateYCallback, NULL, 0);
		ply_set_read_cb(plyfile, "vertex", "z", CoordinateZCallback, NULL, 0);
		ntriangles =
		ply_set_read_cb(plyfile, "face", "vertex_indices", FaceCallback, 0, 0);	
		
		// Create data buffer		
		buildingBuffer.vertexBuffer   = new float[nvertices*3];
		buildingBuffer.normalBuffer   = new float[nvertices*3];
		buildingBuffer.tangentBuffer  = new float[nvertices*3];
		buildingBuffer.indexBuffer    = new unsigned int[ntriangles*3];
		buildingBuffer.numberOfNormal = new int[nvertices];
	
		// Pro-process on normals
		for(int i=0; i<nvertices;++i) {
			buildingBuffer.normalBuffer[i*3+0] = 0.f;
			buildingBuffer.normalBuffer[i*3+1] = 0.f;
			buildingBuffer.normalBuffer[i*3+2] = 0.f;
			buildingBuffer.numberOfNormal[i] = 0;
		}
		
		// Lancement de la lecture du fichier
		currentVertexIndex = 0;			
		currentFaceIndex = 0;
		if (!ply_read(plyfile)) return false;
		// Fermeture du fichier
		ply_close(plyfile);
			
		// Post-process on normals
		for(int i=0; i<nvertices;++i) {
			buildingBuffer.normalBuffer[i*3+0] /= (float)buildingBuffer.numberOfNormal[i];
			buildingBuffer.normalBuffer[i*3+1] /= (float)buildingBuffer.numberOfNormal[i];
			buildingBuffer.normalBuffer[i*3+2] /= (float)buildingBuffer.numberOfNormal[i];
		}
			
		// Create buffer
		TIBufferPointer vertexBuffer, normalBuffer, indexBuffer, tangentBuffer;
		vertexBuffer 	= Geometry::IBuffer::CreateBuffer(Rendering::VERTEX_BUFFER,nvertices);	
		normalBuffer 	= Geometry::IBuffer::CreateBuffer(Rendering::NORMAL_BUFFER,nvertices);	
		//tangentBuffer 	= Geometry::IBuffer::CreateBuffer(Rendering::TANGENT_BUFFER,nvertices);	
		indexBuffer 	= Geometry::IBuffer::CreateBuffer(Rendering::INDEX_BUFFER,ntriangles*3);	
		
		// Load data
		vertexBuffer->Load(buildingBuffer.vertexBuffer);
		normalBuffer->Load(buildingBuffer.normalBuffer);
		//tangentBuffer->Load(buildingBuffer.tangentBuffer);
		indexBuffer->Load(buildingBuffer.indexBuffer);
		
		// Create mesh
		TMeshPointer mesh;
		mesh = Mesh::CreateMesh(Rendering::TRIANGLE_MESH, true);
		mesh->AddBuffer(vertexBuffer);
		mesh->AddBuffer(normalBuffer);
		//mesh->AddBuffer(tangentBuffer);
		mesh->AddBuffer(indexBuffer);
		
		// Delete data buffer
		delete[] buildingBuffer.vertexBuffer;
		delete[] buildingBuffer.normalBuffer;
		delete[] buildingBuffer.tangentBuffer;
		delete[] buildingBuffer.indexBuffer;
		delete[] buildingBuffer.numberOfNormal;
		
        return mesh;
	}
}
